package zpp_nape.shape;
import zpp_nape.Config;
import zpp_nape.Const;
import zpp_nape.util.Flags;
import DummyNapeMain;
import zpp_nape.util.Math;
import zpp_nape.util.Names;
import zpp_nape.util.Pool;
import zpp_nape.util.Lists;
import zpp_nape.shape.Circle;
import zpp_nape.shape.Edge;
import zpp_nape.space.Space;
import zpp_nape.shape.Polygon;
import zpp_nape.phys.FeatureMix;
import zpp_nape.phys.FluidProperties;
import zpp_nape.phys.Material;
import zpp_nape.phys.Body;
import zpp_nape.geom.AABB;
import zpp_nape.geom.Distance;
import zpp_nape.geom.Mat23;
import zpp_nape.geom.Vec2;
import zpp_nape.geom.VecMath;
import zpp_nape.geom.Collide;
import zpp_nape.dynamics.Arbiter;
import zpp_nape.dynamics.Contact;
import zpp_nape.dynamics.InteractionFilter;
import zpp_nape.constraint.Constraint;
import zpp_nape.dynamics.SpaceArbiterList;
import zpp_nape.constraint.Matrices;
import zpp_nape.constraint.PivotJoint;
import zpp_nape.constraint.WeldJoint;
import nape.util.Flags;
import nape.util.Lists;
import nape.util.Debug;
import nape.space.Space;
import nape.shape.Circle;
import nape.shape.Polygon;
import nape.shape.Edge;
import nape.shape.Shape;
import nape.phys.FluidProperties;
import nape.phys.Material;
import nape.phys.Body;
import nape.geom.AABB;
import nape.geom.Geom;
import nape.geom.Mat23;
import nape.geom.Vec2;
import nape.dynamics.Contact;
import nape.dynamics.Arbiter;
import nape.dynamics.InteractionFilter;
#if swc@:keep#end class ZPP_Shape{
    public var outer:Shape;
    public var body:ZPP_Body;
    public var type:Int;
    static var nextId=0;
    public var id:Int;
    #if(flash9&&flib)@:ns("flibdel")#end public inline function isCircle()return type==ZPP_Flags.id_ShapeType_CIRCLE#if(flash9&&flib)@:ns("flibdel")#end public inline function isPolygon()return type==ZPP_Flags.id_ShapeType_POLYGON public var area:Float;
    public var zip_area_inertia:Bool;
    public var inertia:Float;
    public var angDrag:Float;
    public var zip_angDrag:Bool;
    public var localCOMx:Float;
    public var localCOMy:Float;
    public var zip_localCOM:Bool;
    public var worldCOMx:Float;
    public var worldCOMy:Float;
    public var zip_worldCOM:Bool;
    public var wrap_localCOM:Vec2;
    public var wrap_worldCOM:Vec2;
    public var circle:ZPP_Circle;
    public var polygon:ZPP_Polygon;
    public var material:ZPP_Material;
    public var filter:ZPP_InteractionFilter;
    public var fluidProperties:ZPP_FluidProperties;
    public var fluidEnabled:Bool;
    public var sweep:ZPP_SweepData;
    public var aabb:ZPP_AABB;
    public var zip_aabb:Bool;
    #if(flash9&&flib)@:ns("flibdel")#end public inline function validate_aabb(){
        if(zip_aabb){
            if(body!=null){
                zip_aabb=false;
                if(isCircle())circle.__validate_aabb();
                else polygon.__validate_aabb();
            }
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_aabb(){
        zip_aabb=true;
        if(body!=null)body.invalidate_aabb();
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function validate_area_inertia(){
        if(zip_area_inertia){
            zip_area_inertia=false;
            if(isCircle())circle.__validate_area_inertia();
            else polygon.__validate_area_inertia();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function validate_angDrag(){
        if(zip_angDrag){
            zip_angDrag=false;
            if(isCircle())circle.__validate_angDrag();
            else polygon.__validate_angDrag();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function validate_localCOM(){
        if(zip_localCOM){
            zip_localCOM=false;
            if(isPolygon())polygon.__validate_localCOM();
            if(wrap_localCOM!=null){
                wrap_localCOM.zpp_inner.x=localCOMx;
                wrap_localCOM.zpp_inner.y=localCOMy;
                {
                    #if NAPE_ASSERT var res={
                        !({
                            #if flash9 var ret:Bool=untyped __global__["isNaN"](wrap_localCOM.zpp_inner.x);
                            ret;
                            #else Math.isNaN(wrap_localCOM.zpp_inner.x);
                            #end
                        });
                    };
                    if(!res)throw "assert("+"!assert_isNaN(wrap_localCOM.zpp_inner.x)"+") :: "+("vec_set(in n: "+"wrap_localCOM.zpp_inner."+",in x: "+"localCOMx"+",in y: "+"localCOMy"+")");
                    #end
                };
                {
                    #if NAPE_ASSERT var res={
                        !({
                            #if flash9 var ret:Bool=untyped __global__["isNaN"](wrap_localCOM.zpp_inner.y);
                            ret;
                            #else Math.isNaN(wrap_localCOM.zpp_inner.y);
                            #end
                        });
                    };
                    if(!res)throw "assert("+"!assert_isNaN(wrap_localCOM.zpp_inner.y)"+") :: "+("vec_set(in n: "+"wrap_localCOM.zpp_inner."+",in x: "+"localCOMx"+",in y: "+"localCOMy"+")");
                    #end
                };
            };
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function validate_worldCOM(){
        if(zip_worldCOM){
            if(body!=null){
                zip_worldCOM=false;
                validate_localCOM();
                body.validate_axis();
                {
                    worldCOMx=body.posx+(body.axisy*localCOMx-body.axisx*localCOMy);
                    worldCOMy=body.posy+(localCOMx*body.axisx+localCOMy*body.axisy);
                };
                if(wrap_worldCOM!=null){
                    wrap_worldCOM.zpp_inner.x=worldCOMx;
                    wrap_worldCOM.zpp_inner.y=worldCOMy;
                    {
                        #if NAPE_ASSERT var res={
                            !({
                                #if flash9 var ret:Bool=untyped __global__["isNaN"](wrap_worldCOM.zpp_inner.x);
                                ret;
                                #else Math.isNaN(wrap_worldCOM.zpp_inner.x);
                                #end
                            });
                        };
                        if(!res)throw "assert("+"!assert_isNaN(wrap_worldCOM.zpp_inner.x)"+") :: "+("vec_set(in n: "+"wrap_worldCOM.zpp_inner."+",in x: "+"worldCOMx"+",in y: "+"worldCOMy"+")");
                        #end
                    };
                    {
                        #if NAPE_ASSERT var res={
                            !({
                                #if flash9 var ret:Bool=untyped __global__["isNaN"](wrap_worldCOM.zpp_inner.y);
                                ret;
                                #else Math.isNaN(wrap_worldCOM.zpp_inner.y);
                                #end
                            });
                        };
                        if(!res)throw "assert("+"!assert_isNaN(wrap_worldCOM.zpp_inner.y)"+") :: "+("vec_set(in n: "+"wrap_worldCOM.zpp_inner."+",in x: "+"worldCOMx"+",in y: "+"worldCOMy"+")");
                        #end
                    };
                };
            }
        }
    }
    public function getworldCOM(){
        if(body==null)throw "Error: worldCOM only makes sense when Shape belongs to a Body";
        validate_worldCOM();
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_area_inertia(){
        zip_area_inertia=true;
        if(body!=null){
            body.invalidate_localCOM();
            body.invalidate_mass();
            body.invalidate_inertia();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_angDrag(){
        zip_angDrag=true;
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_localCOM(){
        zip_localCOM=true;
        invalidate_area_inertia();
        invalidate_angDrag();
        invalidate_worldCOM();
        if(body!=null)body.invalidate_localCOM();
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_worldCOM(){
        zip_worldCOM=true;
        invalidate_aabb();
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_material(flags:Int){
        if((flags&ZPP_Material.WAKE)!=0)wake();
        if((flags&ZPP_Material.ARBITERS)!=0){
            if(body!=null)body.refreshArbiters();
        }
        if((flags&ZPP_Material.PROPS)!=0){
            if(body!=null){
                body.invalidate_localCOM();
                body.invalidate_mass();
                body.invalidate_inertia();
            }
        }
        if((flags&ZPP_Material.ANGDRAG)!=0){
            invalidate_angDrag();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_filter()wake()#if(flash9&&flib)@:ns("flibdel")#end public inline function invalidate_fluidprops(){
        if(fluidEnabled)wake();
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function wake(){
        if(body!=null)body.wake();
    }
    function new(type:Int){
        this.type=type;
        id=nextId++;
        aabb=ZPP_AABB.get(0,0,0,0);
        aabb.immutable=true;
        var me=this;
        aabb._validate=function(){
            if(me.body==null)throw "Error: bounds only makes sense when Shape belongs to a Body";
            me.validate_aabb();
        };
        zip_area_inertia=zip_angDrag=zip_localCOM=true;
        {
            localCOMx=0;
            localCOMy=0;
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](localCOMx);
                        ret;
                        #else Math.isNaN(localCOMx);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(localCOMx)"+") :: "+("vec_set(in n: "+"localCOM"+",in x: "+"0"+",in y: "+"0"+")");
                #end
            };
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](localCOMy);
                        ret;
                        #else Math.isNaN(localCOMy);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(localCOMy)"+") :: "+("vec_set(in n: "+"localCOM"+",in x: "+"0"+",in y: "+"0"+")");
                #end
            };
        };
        {
            worldCOMx=0;
            worldCOMy=0;
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](worldCOMx);
                        ret;
                        #else Math.isNaN(worldCOMx);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(worldCOMx)"+") :: "+("vec_set(in n: "+"worldCOM"+",in x: "+"0"+",in y: "+"0"+")");
                #end
            };
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](worldCOMy);
                        ret;
                        #else Math.isNaN(worldCOMy);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(worldCOMy)"+") :: "+("vec_set(in n: "+"worldCOM"+",in x: "+"0"+",in y: "+"0"+")");
                #end
            };
        };
        fluidEnabled=false;
        fluidProperties=null;
        body=null;
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function setMaterial(material:ZPP_Material){
        if(this.material!=material){
            if(!material.shared&&!material.shapes.empty())throw "Error: Material cannot be shared unless it's shared property is set";
            if(this.material!=null)this.material.remShape(this);
            this.material=material;
            material.addShape(this);
            wake();
            if(body!=null)body.refreshArbiters();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function setFilter(filter:ZPP_InteractionFilter){
        if(this.filter!=filter){
            if(!filter.shared&&!filter.shapes.empty())throw "Error: InteractionFilter cannot be shared unless it's shared property is set";
            if(this.filter!=null)this.filter.remShape(this);
            this.filter=filter;
            filter.addShape(this);
            wake();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function setFluid(fluid:ZPP_FluidProperties){
        if(fluidProperties!=fluid){
            if(!fluid.shared&&!fluid.shapes.empty())throw "Error: FluidProperties cannot be shared unless it's shared property is set";
            if(fluidProperties!=null)fluidProperties.remShape(this);
            fluidProperties=fluid;
            fluid.addShape(this);
            if(fluidEnabled)wake();
        }
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function addedToBody(){
        invalidate_worldCOM();
        invalidate_aabb();
    }
    #if(flash9&&flib)@:ns("flibdel")#end public inline function removedFromBody(){}
    #if(flash9&&flib)@:ns("flibdel")#end public inline function copy(){
        var ret:ZPP_Shape=null;
        if(isCircle())ret=circle.__copy();
        else ret=polygon.__copy();
        if(!zip_area_inertia){
            ret.area=area;
            ret.inertia=inertia;
        }
        else ret.invalidate_area_inertia();
        if(!zip_angDrag)ret.angDrag=angDrag;
        else ret.invalidate_angDrag();
        if(!zip_aabb){
            {
                ret.aabb.minx=aabb.minx;
                ret.aabb.miny=aabb.miny;
                {
                    #if NAPE_ASSERT var res={
                        !({
                            #if flash9 var ret:Bool=untyped __global__["isNaN"](ret.aabb.minx);
                            ret;
                            #else Math.isNaN(ret.aabb.minx);
                            #end
                        });
                    };
                    if(!res)throw "assert("+"!assert_isNaN(ret.aabb.minx)"+") :: "+("vec_set(in n: "+"ret.aabb.min"+",in x: "+"aabb.minx"+",in y: "+"aabb.miny"+")");
                    #end
                };
                {
                    #if NAPE_ASSERT var res={
                        !({
                            #if flash9 var ret:Bool=untyped __global__["isNaN"](ret.aabb.miny);
                            ret;
                            #else Math.isNaN(ret.aabb.miny);
                            #end
                        });
                    };
                    if(!res)throw "assert("+"!assert_isNaN(ret.aabb.miny)"+") :: "+("vec_set(in n: "+"ret.aabb.min"+",in x: "+"aabb.minx"+",in y: "+"aabb.miny"+")");
                    #end
                };
            };
            {
                ret.aabb.maxx=aabb.maxx;
                ret.aabb.maxy=aabb.maxy;
                {
                    #if NAPE_ASSERT var res={
                        !({
                            #if flash9 var ret:Bool=untyped __global__["isNaN"](ret.aabb.maxx);
                            ret;
                            #else Math.isNaN(ret.aabb.maxx);
                            #end
                        });
                    };
                    if(!res)throw "assert("+"!assert_isNaN(ret.aabb.maxx)"+") :: "+("vec_set(in n: "+"ret.aabb.max"+",in x: "+"aabb.maxx"+",in y: "+"aabb.maxy"+")");
                    #end
                };
                {
                    #if NAPE_ASSERT var res={
                        !({
                            #if flash9 var ret:Bool=untyped __global__["isNaN"](ret.aabb.maxy);
                            ret;
                            #else Math.isNaN(ret.aabb.maxy);
                            #end
                        });
                    };
                    if(!res)throw "assert("+"!assert_isNaN(ret.aabb.maxy)"+") :: "+("vec_set(in n: "+"ret.aabb.max"+",in x: "+"aabb.maxx"+",in y: "+"aabb.maxy"+")");
                    #end
                };
            };
        }
        else ret.invalidate_aabb();
        ret.material.remShape(ret);
        {
            var o=ret.material;
            {
                #if NAPE_ASSERT var res={
                    o!=null;
                };
                if(!res)throw "assert("+"o!=null"+") :: "+("Free(in T: "+"ZPP_Material"+", in obj: "+"ret.material"+")");
                #end
            };
            o.free();
            o.next=ZPP_Material.zpp_pool;
            ZPP_Material.zpp_pool=o;
        };
        ret.filter.remShape(ret);
        {
            var o=ret.filter;
            {
                #if NAPE_ASSERT var res={
                    o!=null;
                };
                if(!res)throw "assert("+"o!=null"+") :: "+("Free(in T: "+"ZPP_InteractionFilter"+", in obj: "+"ret.filter"+")");
                #end
            };
            o.free();
            o.next=ZPP_InteractionFilter.zpp_pool;
            ZPP_InteractionFilter.zpp_pool=o;
        };
        if(material.shared)ret.material=material;
        else ret.material=material.copy();
        ret.material.addShape(ret);
        if(filter.shared)ret.filter=filter;
        else ret.filter=filter.copy();
        ret.filter.addShape(ret);
        if(fluidProperties!=null){
            if(fluidProperties.shared)ret.fluidProperties=fluidProperties;
            else ret.fluidProperties=fluidProperties.copy();
            ret.fluidProperties.addShape(ret);
        }
        ret.fluidEnabled=fluidEnabled;
        return ret.outer;
    }
}
